#include "include/kconst.h"
#include "include/proc.h"
#include "include/tty.h"
#include "include/type.h"
#include "include/keyboard.h"
#include "include/klib.h"
#include "include/console.h"
#include "include/global.h"


#define TTY_FIRST     (tty_table)
#define TTY_END       (tty_table + NR_CONSOLES)

extern TTY tty_table[NR_CONSOLES];
extern CONSOLE console_table[NR_CONSOLES];

extern u32 nr_current_console;
u32 pos;
u32 off;
u32 from_cxy(u8 color, u8 x, u8 y)
{

}
u32 from_postion(u32 pos)
{
    u32 info = 0x000f0000;
    u32 x = pos / 80;
    u32 y = pos % 80;
    info |= (x & 0xFF) << 8;
    info |= y & 0xFF;
    return info;
}

void init_tty(TTY *p_tty)
{
    p_tty->inbuf_count = 0;
    p_tty->p_inbuf_head = p_tty->p_inbuf_tail = p_tty->in_buf;

    init_screen(p_tty);

}

static void tty_do_read(TTY *p_tty)
{
    if (is_current_console(p_tty->p_console))
    {
        keyboard_read(p_tty);
        
    }
}
static void tty_do_write(TTY *p_tty)
{
    
    if (p_tty->inbuf_count)
    {
        char ch = *(p_tty->p_inbuf_tail);
        p_tty->p_inbuf_tail++;
        
        if (p_tty->p_inbuf_tail == p_tty->in_buf + TTY_IN_BYTES)
        {
            p_tty->p_inbuf_tail = p_tty->in_buf;
        }
        p_tty->inbuf_count--;
        
        out_char(p_tty->p_console, ch);
    }
}

void task_tty()
{   
    TTY* p_tty;
    dis_char_pos = 400;
    init_keyboard();
    for (p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++)
    {
        init_tty(p_tty);
    }
    select_console(0);
    while (1)
    {
        
        for (p_tty = TTY_FIRST; p_tty < TTY_END; p_tty++)
        {
            tty_do_read(p_tty);
            tty_do_write(p_tty);
        }
    }
    
    
}

static void put_key(TTY *p_tty, u32 key)
{
    if (p_tty->inbuf_count < TTY_IN_BYTES)
    {
        *(p_tty->p_inbuf_head) = key;
        p_tty->p_inbuf_head++;
        if (p_tty->p_inbuf_head == p_tty->in_buf + TTY_IN_BYTES)
        {
            p_tty->p_inbuf_head = p_tty->in_buf;
        }
        p_tty->inbuf_count++;
    }
}

int tty_write(TTY* p_tty, char *buf, int len)
{
    char *p = buf;
    int i = len;
    while (i) 
    {
        out_char(p_tty->p_console, *p++);
        --i;
    }
}

int sys_printx(int _unused1, int _unused2, char *s, PROCESS *p_proc)
{
    const char *p;
    char ch;
    char reenter_err[] = "  k_reenter is incorrect for unknown reason";
    reenter_err[0] = MAG_CH_PANIC;
    
    if (k_reenter == 0) /* 从用户态调用 */
    {
        p = va2la(proc2pid(p_proc), s);
    } 
    else if (k_reenter > 0) /* 从内核态调用 */
    {
        p = s;
    }
    else /* 错误 */
    {
        p = reenter_err;
    }

    if ((*p) == MAG_CH_PANIC || 
        (*p == MAG_CH_ASSERT && p_proc_ready < &proc_table[NR_TASKS]))
    {
        disable_int();
        char *v = (char*) V_MEM_BASE;
        const char *q = p + 1;
        while (v < (char *)(V_MEM_BASE + V_MEM_SIZE))
        {
            *v++ = *q++;
            *v++ = 0x0004; //文字颜色,红色
            if (!*q)
            {
                while (((int)v - V_MEM_BASE) % (160*16))
                {
                    v++;
                    *v++ = 0x000f;
                }
                q = p + 1;
            }
        }
        __asm__ __volatile__("hlt");
    }
    
    while ((ch = *p++) != 0)
    {
        if (ch == MAG_CH_PANIC || ch == MAG_CH_ASSERT)
        {
            continue;
        }
        out_char(tty_table[p_proc->nr_tty].p_console, ch);
    }
}

void in_process(TTY *p_tty,u32 key)
{
    char output[2] = {'\0','\0'};
    disp_u32(key, 0x00f0A01);
    if (!(key & FLAG_EXT))
    {
        put_key(p_tty, key);
        
    } else {

        switch (key & 0x1FF)
        {
            case F1:
            case F2:
            case F3:
            case F4:
                if (key & FLAG_SHIFT_L)
                {
                    select_console((key & 0x1FF) - F1);
                }
                break;
            case UP:
                if (key & FLAG_SHIFT_L)
                {
                    scroll_screen(p_tty->p_console, 0x1);
                }
                break;
            case DOWN:
                if (key & FLAG_SHIFT_L)
                {
                    scroll_screen(p_tty->p_console, 0x2);
                }
                break;
            case ENTER:
                put_key(p_tty, '\n');
                break;
            case BACKSPACE:
                put_key(p_tty, '\b');
                break;
            default:
                break;
        }
    }
}